package dc.medicine.com.okhttplib.request;

import android.util.Log;

import org.json.JSONException;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import dc.medicine.com.okhttplib.OkHttpUtils;
import dc.medicine.com.okhttplib.callback.AbsCallback;
import dc.medicine.com.okhttplib.model.HttpHeaders;
import dc.medicine.com.okhttplib.model.HttpParams;
import okhttp3.Call;


import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.internal.http.HeaderParser;

/**
 * Created by hp on 2016/7/14.
 */
public abstract class BaseRequest<R extends BaseRequest> {


    protected String url;
    protected Object tag;
    protected long readTimeOut;
    protected long writeTimeOut;
    protected long connectTimeout;
    private AbsCallback mCallback;
    protected HttpHeaders headers = new HttpHeaders();              //添加的header

    private HttpUrl httpUrl;

    protected HttpParams params = new HttpParams();                 //添加的param

    public BaseRequest(String url) {
        this.url = url;
        httpUrl = HttpUrl.parse(url);
        OkHttpUtils okHttpUtils = OkHttpUtils.getInstance();

        //添加公共请求参数
//        if (okHttpUtils.getCommonHeaders() != null) {
//            headers.put(okHttpUtils.getCommonHeaders());
//        }

    }

    /**
     * 通用的拼接请求头
     */
    protected Request.Builder appendHeaders(Request.Builder requestBuilder) {
        Headers.Builder headerBuilder = new Headers.Builder();
        ConcurrentHashMap<String, String> headerMap = headers.headersMap;
        if (headerMap.isEmpty()) return requestBuilder;
        for (String key : headerMap.keySet()) {
            headerBuilder.add(key, headerMap.get(key));
        }
        requestBuilder.headers(headerBuilder.build());
        return requestBuilder;

    }

    public R url(String url) {
        this.url = url;
        return (R) this;
    }

    public R tag(Object tag) {
        this.tag = tag;
        return (R) this;
    }

    public R readTimeOut(long readTimeOut) {
        this.readTimeOut = readTimeOut;
        return (R) this;
    }

    public R writeTimeOut(long writeTimeOut) {
        this.writeTimeOut = writeTimeOut;
        return (R) this;
    }

    public R connTimeOut(long connTimeOut) {
        this.connectTimeout = connTimeOut;
        return (R) this;
    }

    public R setCallback(AbsCallback callback) {
        this.mCallback = callback;
        return (R) this;
    }

    public R paramsApp(String key,String value) {
        params.appsParmas.put(key,value);
        return (R) this;
    }

    public R paramsSYS(String key,String value) {
        params.systemParmas.put(key, value);
        return (R) this;
    }

    public HttpParams getParams() {
        return params;
    }


    /**
     * 根据不同的请求方式和参数，生成不同的RequestBody
     */
    protected abstract RequestBody generateRequestBody();

    /**
     * 根据不同的请求方式，将RequestBody转换成Request对象
     */
    protected abstract Request generateRequest(RequestBody requestBody);


    /**
     * 对请求body进行包装，用于回调上传进度
     */
    protected RequestBody wrapRequestBody(RequestBody requestBody) {
        ProgressRequestBody progressRequestBody = new ProgressRequestBody(requestBody);
        progressRequestBody.setListener(new ProgressRequestBody.Listener() {
            @Override
            public void onRequestProgress(final long bytesWritten, final long contentLength, final long networkSpeed) {
                OkHttpUtils.getInstance().getDelivery().post(new Runnable() {
                    @Override
                    public void run() {
                        if (mCallback != null) {
                            mCallback.upProgress(bytesWritten, contentLength, bytesWritten * 1.0f / contentLength, networkSpeed);
                        }
                    }
                });
            }
        });
        return progressRequestBody;
    }

    /**
     * 阻塞方法，同步请求执行
     */
    public Response execute() throws IOException {
        //添加缓存头和其他的公共头，同步请求不做缓存，缓存为空
        RequestBody requestBody = generateRequestBody();
        final Request request = generateRequest(wrapRequestBody(requestBody));
        Call call = generateCall(request);
        return call.execute();
    }

    /**
     * 根据当前的请求参数，生成对应的 Call 任务
     */
    protected Call generateCall(Request request) {

        if (readTimeOut <= 0 && writeTimeOut <= 0 && connectTimeout <= 0) {
            return new OkHttpClient().newCall(request);
        } else {
            OkHttpClient.Builder newClientBuilder = OkHttpUtils.getInstance().getOkHttpClient().newBuilder();
            if (readTimeOut > 0) newClientBuilder.readTimeout(readTimeOut, TimeUnit.MILLISECONDS);
            if (writeTimeOut > 0)
                newClientBuilder.writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS);
            if (connectTimeout > 0)
                newClientBuilder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS);
            return newClientBuilder.build().newCall(request);
        }

    }

    /**
     * 非阻塞方法，异步请求，但是回调在子线程中执行
     */
    public <T> void execute(AbsCallback<T> callback) {
        mCallback = callback;
        if (mCallback == null) mCallback = AbsCallback.CALLBACK_DEFAULT;
        //请求之前获取缓存信息，添加缓存头和其他的公共头


        //请求执行前UI线程调用
        mCallback.onBefore(this);
        RequestBody requestBody = generateRequestBody();
        Request request = generateRequest(requestBody);
        Call call = generateCall(request);

        call.enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                //请求失败，一般为url地址错误，网络错误等
                sendFailResultCallback(false, call, null, e, mCallback);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException{
                int responseCode = response.code();
                String result = null;
                result=response.body().string();
                Log.d("info","responseCode:"+responseCode+"-------response:"+result);
                try {
                    T data = (T) mCallback.parseNetworkResponse(result);
                    sendSuccessResultCallback(false, data, call, response, mCallback);
                }catch (Exception e) {
                    e.printStackTrace();
                    sendFailResultCallback(false, call, null, null, mCallback);
                    Log.e("info","respon:"+e.getMessage());
                }
            }
        });
    }

    private <T> void sendFailResultCallback(final boolean b, final Call call, final Response response, final IOException e, final AbsCallback mCallback) {

        OkHttpUtils.getInstance().getDelivery().post(new Runnable() {
            @Override
            public void run() {
                mCallback.onError(call, response, e);
                mCallback.onAfter(b, null);
            }
        });
    }

    /**
     * 成功回调，发送到主线程
     */
    private <T> void sendSuccessResultCallback(final boolean isFromCache, final T t, //
                                               final Call call, final Response response, final AbsCallback<T> callback) {

        OkHttpUtils.getInstance().getDelivery().post(new Runnable() {
            @Override
            public void run() {
                callback.onResponse(t);//请求成功回调 （UI线程）
                callback.onAfter(isFromCache, t);//请求结束回调 （UI线程）
            }
        });
    }

    /**
     * 生成类是表单的请求体
     */
    protected RequestBody generateMultipartRequestBody(MediaType type) {
//        FormBody.Builder bodyBuilder = new FormBody.Builder();
//        bodyBuilder.add("jsonObject", params.appsParmas.toString());
//        bodyBuilder.add("keyParams", params.systemParmas.toString());
//        bodyBuilder.add(params.appsParmas.toString());

       // RequestBody body = RequestBody.create(type, params.appsParmas.toString().getBytes());

        StringBuilder builder = new StringBuilder();
        Iterator<String> it2 = params.appsParmas.keySet().iterator();
        while (it2.hasNext()) {
            String key = it2.next();
            builder.append(key);
            builder.append("=");
            builder.append(params.appsParmas.get(key));
            builder.append("&");
        }

        builder.deleteCharAt(builder.length() - 1);
        Log.d("info",builder.toString());
        RequestBody body = RequestBody.create(type, builder.toString().getBytes());
        return body;
    }


}
